package com.ladlee.parking.pay.v3.handle.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ladlee.parking.entity.PayChannel;
import com.ladlee.parking.pay.v3.core.PayHttpResponse;
import com.ladlee.parking.pay.v3.core.WxPayApi;
import com.ladlee.parking.pay.v3.core.WxPayV3Bean;
import com.ladlee.parking.pay.v3.enums.*;
import com.ladlee.parking.pay.v3.handle.PayHandler;
import com.ladlee.parking.pay.v3.model.Amount;
import com.ladlee.parking.pay.v3.model.Payer;
import com.ladlee.parking.pay.v3.model.UnifiedOrderModel;
import com.ladlee.parking.pay.v3.util.PayKit;
import com.ladlee.parking.pay.v3.util.WxPayKit;
import com.ladlee.parking.sequence.seq.Sequence;
import com.ladlee.parking.service.PayChannelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.security.cert.X509Certificate;
import java.util.Map;

/**
 * 微信H5支付处理器
 */
@Slf4j
public class WxWapPayHandler implements PayHandler<UnifiedOrderModel> {

    @Autowired
    PayChannelService payChannelService;
    @Autowired
    WxPayV3Bean wxPayV3Bean;
    @Autowired
    Sequence sequence;

    /**
     * 成功响应标识
     */
    private final static int OK = 200;

    /**
     * 商户 API 证书序列号
     */
    private String serialNo;

    /**
     * 平台序列号
     */
    private String platSerialNo;

    @Override
    public boolean support(String tradeType) {
        return WxTradeType.MWEB.getTradeType().equals(tradeType);
    }

    @Override
    public String handle(UnifiedOrderModel unifiedModel) throws Exception {
        log.info("微信H5统一下单参数 {}", JSONUtil.toJsonStr(unifiedModel));
        try {
            unifiedModel.setAppid(wxPayV3Bean.getAppId());
            unifiedModel.setMchid(wxPayV3Bean.getMchId());
            unifiedModel.setNotify_url("");
            unifiedModel.setOut_trade_no(sequence.nextNo());
            PayHttpResponse payHttpResponse = WxPayApi.v3(
                    RequestMethod.POST,
                    WxDomain.CHINA.getType(),
                    WxApiType.H5_PAY.getType(),
                    unifiedModel.getMchid(),
                    getSerialNumber(),
                    null,
                    wxPayV3Bean.getKeyPath(),
                    JSONUtil.toJsonStr(unifiedModel));
            log.info("统一下单响应：{}", payHttpResponse);
            if (payHttpResponse.getStatus() == OK) {
                // 根据证书序列号查询对应的证书来验证签名结果
                boolean verifySignature = WxPayKit.verifySignature(payHttpResponse, wxPayV3Bean.getPlatformCertPath());
                log.info("verifySignature: {}", verifySignature);
                if (verifySignature) {
                    String body = payHttpResponse.getBody();
                    JSONObject jsonObject = JSONUtil.parseObj(body);
                    String prepayId = jsonObject.getStr("prepay_id");
                    Map<String, String> map = WxPayKit.jsApiCreateSign(wxPayV3Bean.getAppId(), prepayId, wxPayV3Bean.getKeyPath());
                    log.info("唤起支付参数:{}", map);
                    return JSONUtil.toJsonStr(map);
                }
            }
            return JSONUtil.toJsonStr(payHttpResponse);
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        }
    }

    public String getSerialNumber() {
        if (StrUtil.isEmpty(serialNo)) {
            X509Certificate x509Certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getCertPath()));
            serialNo = x509Certificate.getSerialNumber().toString(16).toUpperCase();
        }
        log.info("serialNo:{}", serialNo);
        return serialNo;
    }

    private String getPlatSerialNumber() {
        if (StrUtil.isEmpty(platSerialNo)) {
            // 获取平台证书序列号
            X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Bean.getPlatformCertPath()));
            platSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
        }
        log.info("platSerialNo:{}", platSerialNo);
        return platSerialNo;
    }
}
